﻿using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using SHRIS.MIS.Common.Util;
using SHRIS.MIS.Entity.ScadaData;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SHRIS.MIS.Service.RabbitService
{
    //DeviceAlarmConsumerService
    public class DeviceAlarmConsumerService : BackgroundService
    {
        #region 注入
        private readonly IConnection _rabbitConnection;
        private readonly IModel _channel;
        private readonly string _strMQChannel;
        private readonly string _strMQQueue;
        private readonly string _strMQRoute;
        private readonly string _tableName;


        private ConcurrentQueue<DeviceAlarmEntity> _deviceAlarmEntities = new ConcurrentQueue<DeviceAlarmEntity>();
        public DeviceAlarmConsumerService(IConnection rabbitConnection, string strMQChannel, string strMQQueue, string strMQRoute, string tableName)
        {
            _tableName = tableName;
            _strMQChannel = strMQChannel;
            _strMQQueue = strMQQueue;
            _strMQRoute = strMQRoute;
            _rabbitConnection = rabbitConnection;
            _channel = _rabbitConnection.CreateModel();

            _channel.BasicQos(0, prefetchCount: 10, false); // prefetchCount 可以根据实际情况调整


            _channel.ExchangeDeclare(_strMQChannel, "topic");
            _channel.QueueDeclare(_strMQQueue, true, false, false);
            _channel.QueueBind(_strMQQueue, _strMQChannel, _strMQRoute);
        }
        #endregion

        #region 执行方法
        long start = DateTime.Now.Millisecond;

        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            Task.Run(() => Process(stoppingToken));
            return Task.CompletedTask;
        }

        protected void Process(CancellationToken stoppingToken)
        {
            var consumer = new EventingBasicConsumer(_channel);
            long end = 0L;
            consumer.Received += (model, ea) =>
            {
                var body = ea.Body;
                var message = Encoding.UTF8.GetString(body.ToArray());
                var data = JsonConvert.DeserializeObject<DeviceAlarmEntity>(message);
                data.CreateTime = DateTime.Now;
                data.UpdateTime = DateTime.Now;
                _deviceAlarmEntities.Enqueue(data);
                if (_deviceAlarmEntities.Count % 5 == 0)
                {
                    start = DateTime.Now.Millisecond;
                    var result = PostMesDeviceAlarm(_deviceAlarmEntities);
                    if (result)
                    {
                        _channel.BasicAck(ea.DeliveryTag, true);
                    }
                    else
                    {
                        _channel.BasicNack(ea.DeliveryTag, true, true);
                    }
                    _deviceAlarmEntities.Clear();
                }
                end = DateTime.Now.Millisecond;
                //如果时间大于25s 并且list 的数据小于100 提交 保证时效性
                if (((end - start) > 25) && (_deviceAlarmEntities.Count > 0 && _deviceAlarmEntities.Count < 5))
                {
                    start = DateTime.Now.Millisecond;
                    var result = PostMesDeviceAlarm(_deviceAlarmEntities);
                    if (result)
                    {
                        _channel.BasicAck(ea.DeliveryTag, true);
                    }
                    else
                    {
                        _channel.BasicNack(ea.DeliveryTag, true, true);
                    }
                    _deviceAlarmEntities.Clear();
                }
            };
            _channel.BasicConsume(queue: _strMQQueue, autoAck: false, consumer: consumer);
        }
        #endregion

        #region 公共方法
        private bool PostMesDeviceAlarm(ConcurrentQueue<DeviceAlarmEntity> _deviceStatusEntities)
        {
            try
            {
                BulkInserter.AddByBluckCopy(_tableName, _deviceStatusEntities);
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        #endregion
    }
}
